/*
 * The MIT License
 * Copyright (c) 2012 kc4.org
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package org.kc4.sso.auth;

import java.net.InetAddress;
import java.net.UnknownHostException;

import javax.servlet.ServletContext;

import org.apache.http.HttpHost;

/**
 * SSO認証で使用される、コンテキストパラメーターベースの各種設定です。
 * コンテキストパラメーターとして設定できる値は次のとおりです。
 * <pre>{@code
 * <context-param>
 * 	<description>
 * 		SSO クライアントと、SSO プロバイダがクロスドメイン上に存在し、
 * 		外部ネットワークへのアクセスに、プロキシの利用が必要な場合に
 * 		設定します。プロキシの書式は [ホスト名](:[ポート番号]) です。
 * 		デフォルトでは、使用されません。
 * 	</description>
 * 	<param-name>SSOProxy</param-name>
 * 	<param-value>localhost:8080</param-value>
 * </context-param>
 * <context-param>
 * 	<description>
 * 		SSO プロバイダの URL を設定します。
 * 		SSO クライアントとなる Web アプリケーションでは必須設定項目です。
 * 	</description>
 * 	<param-name>ProviderURL</param-name>
 * 	<param-value>http://hostname/sso-provider/</param-value>
 * </context-param>
 * <context-param>
 * 	<description>
 * 		コールバックURLパラメーターの名前を設定します。
 * 		デフォルト値は、_callback です。
 * 	</description>
 * 	<param-name>NamingOfCallback</param-name>
 * 	<param-value>_callback</param-value>
 * </context-param>
 * <context-param>
 * 	<description>
 * 		公開鍵パラメーターの名前を設定します。
 * 		デフォルト値は、_pubkey です。
 * 	</description>
 * 	<param-name>NamingOfPublickey</param-name>
 * 	<param-value>_pubkey</param-value>
 * </context-param>
 * <context-param>
 * 	<description>
 * 		コンテキストURLパラメーターの名前を設定します。
 * 		デフォルト値は、_ctxurl です。
 * 	</description>
 * 	<param-name>NamingOfContextUrl</param-name>
 * 	<param-value>_ctxurl</param-value>
 * </context-param>
 * <context-param>
 * 	<description>
 * 		認証トークンパラメーターの名前を設定します。
 * 		デフォルト値は、_auth です。
 * 	</description>
 * 	<param-name>NamingOfAuthorizationToken</param-name>
 * 	<param-value>_auth</param-value>
 * </context-param>
 * <context-param>
 * 	<description>
 * 		暗号化された共通鍵パラメーターの名前を設定します。
 * 		デフォルト値は、_comkey です。
 * 	</description>
 * 	<param-name>NamingOfEncryptedCommonkey</param-name>
 * 	<param-value>_comkey</param-value>
 * </context-param>
 * <context-param>
 * 	<description>
 * 		ユーザーオブジェクトパラメーターの名前を設定します。
 * 		デフォルト値は、_usrobj です。
 * 	</description>
 * 	<param-name>NamingOfUserObject</param-name>
 * 	<param-value>_usrobj</param-value>
 * </context-param>
 * <context-param>
 * 	<description>
 * 		非対称暗号器パラメーターの名前を設定します。
 * 		デフォルト値は、_aciph です。
 * 	</description>
 * 	<param-name>NamingOfAsymmetricCipher</param-name>
 * 	<param-value>_aciph</param-value>
 * </context-param>
 * <context-param>
 * 	<description>
 * 		対称暗号器パラメーターの名前を設定します。
 * 		デフォルト値は、_sciph です。
 * 	</description>
 * 	<param-name>NamingOfSymmetricCipher</param-name>
 * 	<param-value>_sciph</param-value>
 * </context-param>
 * <context-param>
 * 	<description>
 * 		レルムパラメーターの名前を設定します。
 * 		デフォルト値は、_realm です。
 * 	</description>
 * 	<param-name>NamingOfRealm</param-name>
 * 	<param-value>_realm</param-value>
 * </context-param>
 * <context-param>
 * 	<description>
 * 		ユーザー名パラメーターの名前を設定します。
 * 		デフォルト値は、_username です。
 * 	</description>
 * 	<param-name>NamingOfUsername</param-name>
 * 	<param-value>_username</param-value>
 * </context-param>
 * <context-param>
 * 	<description>
 * 		パスワードパラメーターの名前を設定します。
 * 		デフォルト値は、_password です。
 * 	</description>
 * 	<param-name>NamingOfPassword</param-name>
 * 	<param-value>_password</param-value>
 * </context-param>
 * <context-param>
 * 	<description>
 * 		サインオントークンパラメーターの名前を設定します。
 * 		デフォルト値は、_signon です。
 * 	</description>
 * 	<param-name>NamingOfSignonToken</param-name>
 * 	<param-value>_signon</param-value>
 * </context-param>
 * <context-param>
 * 	<description>
 * 		サインオフ署名パラメーターの名前を設定します。
 * 		デフォルト値は、_signoff です。
 * 	</description>
 * 	<param-name>NamingOfSignoffSignature</param-name>
 * 	<param-value>_signoff</param-value>
 * </context-param>
 * }</pre>
 *
 * @author yoichi kikuchi
 * @since 1.0
 * @version 1.0
 */
public class SSOContextParameters {

	private static final String SSO_PROXY = "SSOProxy";
	private static final String PROVIDER_URL = "ProviderURL";

	private static final String NAMING_OF_CALLBACK = "NamingOfCallback";
	private static final String NAMING_OF_PUBLICKEY = "NamingOfPublickey";
	private static final String NAMING_OF_CONTEXT_URL = "NamingOfContextUrl";
	private static final String NAMING_OF_AUTHORIZATION_TOKEN = "NamingOfAuthorizationToken";
	private static final String NAMING_OF_ENCRYPTED_COMMONKEY = "NamingOfEncryptedCommonkey";
	private static final String NAMING_OF_USER_OBJECT = "NamingOfUserObject";
	private static final String NAMING_OF_ASYMMETRIC_CIPHER = "NamingOfAsymmetricCipher";
	private static final String NAMING_OF_SYMMETRIC_CIPHER = "NamingOfSymmetricCipher";
	private static final String NAMING_OF_REALM = "NamingOfRealm";
	private static final String NAMING_OF_USERNAME = "NamingOfUsername";
	private static final String NAMING_OF_PASSWORD = "NamingOfPassword";
	private static final String NAMING_OF_SIGNON_TOKEN = "NamingOfSignonToken";
	private static final String NAMING_OF_SIGNOFF_SIGNATURE = "NamingOfSignoffSignature";

	private static SSOContextParameters instance;

	private HttpHost proxy = null;
	private String providerURL = "";
	private String contextURL = "";

	private String namingOfCallback = "_callback";
	private String namingOfPublickey = "_pubkey";
	private String namingOfContextUrl = "_ctxurl";
	private String namingOfAuthorizationToken = "_auth";
	private String namingOfEncryptedCommonkey = "_comkey";
	private String namingOfUserObject = "_usrobj";
	private String namingOfAsymmetricCipher = "_aciph";
	private String namingOfSymmetricCipher = "_sciph";
	private String namingOfRealm = "_realm";
	private String namingOfUsername = "_username";
	private String namingOfPassword = "_password";
	private String namingOfSignonToken = "_signon";
	private String namingOfSignoffSignature = "_signoff";

	/**
	 * {@link SSOContextParameters} インスタンスを取得します。
	 *
	 * @return {@link SSOContextParameters} インスタンス。
	 */
	public static SSOContextParameters getInstance() {

		return getInstance(null);
	}

	/**
	 * {@link SSOContextParameters} インスタンスを取得します。
	 *
	 * @param context サーブレットコンテキスト。
	 * @return {@link SSOContextParameters} インスタンス。
	 */
	public static SSOContextParameters getInstance(ServletContext context) {

		if (instance == null) {

			instance = new SSOContextParameters(context);
		}

		return instance;
	}

	/**
	 * インスタンスを生成し、{@link ServletContext} からパラメーターを読み込みます。
	 *
	 * @param context サーブレットコンテキスト。
	 */
	protected SSOContextParameters(ServletContext context) {

		if (context == null) {

			return;
		}

		String name;

		try {

			name = InetAddress.getLocalHost().getHostName() + context.getContextPath();
			this.setContextURL(name);
		}
		catch (UnknownHostException e) {

			throw new IllegalStateException(e);
		}

		name = context.getInitParameter(SSO_PROXY);
		if (name != null && !name.trim().isEmpty()) {

			String[] s = name.split(":");
			String host = s[0];
			int port = -1;

			if (s.length >= 2) {

				port = Integer.valueOf(s[1]);
			}

			if (port >= 0) {

				this.setProxy(new HttpHost(host, port));
			}
			else {

				this.setProxy(new HttpHost(host));
			}
		}

		name = context.getInitParameter(PROVIDER_URL);
		if (name != null && !name.trim().isEmpty()) {

			this.setProviderURL(name);
		}

		name = context.getInitParameter(NAMING_OF_CALLBACK);
		if (name != null && !name.trim().isEmpty()) {

			this.setNamingOfCallback(name.trim());
		}

		name = context.getInitParameter(NAMING_OF_PUBLICKEY);
		if (name != null && !name.trim().isEmpty()) {

			this.setNamingOfPublickey(name.trim());
		}

		name = context.getInitParameter(NAMING_OF_CONTEXT_URL);
		if (name != null && !name.trim().isEmpty()) {

			this.setNamingOfContextUrl(name.trim());
		}

		name = context.getInitParameter(NAMING_OF_AUTHORIZATION_TOKEN);
		if (name != null && !name.trim().isEmpty()) {

			this.setNamingOfAuthorizationToken(name.trim());
		}

		name = context.getInitParameter(NAMING_OF_ENCRYPTED_COMMONKEY);
		if (name != null && !name.trim().isEmpty()) {

			this.setNamingOfEncryptedCommonkey(name.trim());
		}

		name = context.getInitParameter(NAMING_OF_USER_OBJECT);
		if (name != null && !name.trim().isEmpty()) {

			this.setNamingOfUserObject(name.trim());
		}

		name = context.getInitParameter(NAMING_OF_ASYMMETRIC_CIPHER);
		if (name != null && !name.trim().isEmpty()) {

			this.setNamingOfAsymmetricCipher(name.trim());
		}

		name = context.getInitParameter(NAMING_OF_SYMMETRIC_CIPHER);
		if (name != null && !name.trim().isEmpty()) {

			this.setNamingOfSymmetricCipher(name.trim());
		}

		name = context.getInitParameter(NAMING_OF_REALM);
		if (name != null && !name.trim().isEmpty()) {

			this.setNamingOfRealm(name.trim());
		}

		name = context.getInitParameter(NAMING_OF_USERNAME);
		if (name != null && !name.trim().isEmpty()) {

			this.setNamingOfUsername(name.trim());
		}

		name = context.getInitParameter(NAMING_OF_PASSWORD);
		if (name != null && !name.trim().isEmpty()) {

			this.setNamingOfPassword(name.trim());
		}

		name = context.getInitParameter(NAMING_OF_SIGNON_TOKEN);
		if (name != null && !name.trim().isEmpty()) {

			this.setNamingOfSignonToken(name.trim());
		}

		name = context.getInitParameter(NAMING_OF_SIGNOFF_SIGNATURE);
		if (name != null && !name.trim().isEmpty()) {

			this.setNamingOfSignoffSignature(name.trim());
		}
	}

	/**
	 * namingOfCallback を取得します。
	 *
	 * @return namingOfCallback オブジェクト。
	 */
	public String getNamingOfCallback() {
		return this.namingOfCallback;
	}

	/**
	 * namingOfCallback を設定します。
	 *
	 * @param namingOfCallback namingOfCallback オブジェクト。
	 */
	protected void setNamingOfCallback(String namingOfCallback) {
		this.namingOfCallback = namingOfCallback;
	}

	/**
	 * namingOfPublickey を取得します。
	 *
	 * @return namingOfPublickey オブジェクト。
	 */
	public String getNamingOfPublickey() {
		return this.namingOfPublickey;
	}

	/**
	 * namingOfPublickey を設定します。
	 *
	 * @param namingOfPublickey namingOfPublickey オブジェクト。
	 */
	protected void setNamingOfPublickey(String namingOfPublickey) {
		this.namingOfPublickey = namingOfPublickey;
	}

	/**
	 * namingOfContextUrl を取得します。
	 *
	 * @return namingOfContextUrl オブジェクト。
	 */
	public String getNamingOfContextUrl() {
		return this.namingOfContextUrl;
	}

	/**
	 * namingOfContextUrl を設定します。
	 *
	 * @param namingOfContextUrl namingOfContextUrl オブジェクト。
	 */
	protected void setNamingOfContextUrl(String namingOfContextUrl) {
		this.namingOfContextUrl = namingOfContextUrl;
	}

	/**
	 * namingOfAuthorizationToken を取得します。
	 *
	 * @return namingOfAuthorizationToken オブジェクト。
	 */
	public String getNamingOfAuthorizationToken() {
		return this.namingOfAuthorizationToken;
	}

	/**
	 * namingOfAuthorizationToken を設定します。
	 *
	 * @param namingOfAuthorizationToken namingOfAuthorizationToken オブジェクト。
	 */
	protected void setNamingOfAuthorizationToken(String namingOfAuthorizationToken) {
		this.namingOfAuthorizationToken = namingOfAuthorizationToken;
	}

	/**
	 * namingOfEncryptedCommonkey を取得します。
	 *
	 * @return namingOfEncryptedCommonkey オブジェクト。
	 */
	public String getNamingOfEncryptedCommonkey() {
		return this.namingOfEncryptedCommonkey;
	}

	/**
	 * namingOfEncryptedCommonkey を設定します。
	 *
	 * @param namingOfEncryptedCommonkey namingOfEncryptedCommonkey オブジェクト。
	 */
	protected void setNamingOfEncryptedCommonkey(String namingOfEncryptedCommonkey) {
		this.namingOfEncryptedCommonkey = namingOfEncryptedCommonkey;
	}

	/**
	 * namingOfUserObject を取得します。
	 *
	 * @return namingOfUserObject オブジェクト。
	 */
	public String getNamingOfUserObject() {
		return this.namingOfUserObject;
	}

	/**
	 * namingOfUserObject を設定します。
	 *
	 * @param namingOfUserObject namingOfUserObject オブジェクト。
	 */
	protected void setNamingOfUserObject(String namingOfUserObject) {
		this.namingOfUserObject = namingOfUserObject;
	}

	/**
	 * namingOfAsymmetricCipher を取得します。
	 *
	 * @return namingOfAsymmetricCipher オブジェクト。
	 */
	public String getNamingOfAsymmetricCipher() {
		return this.namingOfAsymmetricCipher;
	}

	/**
	 * namingOfAsymmetricCipher を設定します。
	 *
	 * @param namingOfAsymmetricCipher namingOfAsymmetricCipher オブジェクト。
	 */
	protected void setNamingOfAsymmetricCipher(String namingOfAsymmetricCipher) {
		this.namingOfAsymmetricCipher = namingOfAsymmetricCipher;
	}

	/**
	 * namingOfSymmetricCipher を取得します。
	 *
	 * @return namingOfSymmetricCipher オブジェクト。
	 */
	public String getNamingOfSymmetricCipher() {
		return this.namingOfSymmetricCipher;
	}

	/**
	 * namingOfSymmetricCipher を設定します。
	 *
	 * @param namingOfSymmetricCipher namingOfSymmetricCipher オブジェクト。
	 */
	protected void setNamingOfSymmetricCipher(String namingOfSymmetricCipher) {
		this.namingOfSymmetricCipher = namingOfSymmetricCipher;
	}

	/**
	 * namingOfRealm を取得します。
	 *
	 * @return namingOfRealm オブジェクト。
	 */
	public String getNamingOfRealm() {
		return this.namingOfRealm;
	}

	/**
	 * namingOfRealm を設定します。
	 *
	 * @param namingOfRealm namingOfRealm オブジェクト。
	 */
	protected void setNamingOfRealm(String namingOfRealm) {
		this.namingOfRealm = namingOfRealm;
	}

	/**
	 * namingOfUsername を取得します。
	 *
	 * @return namingOfUsername オブジェクト。
	 */
	public String getNamingOfUsername() {
		return this.namingOfUsername;
	}

	/**
	 * namingOfUsername を設定します。
	 *
	 * @param namingOfUsername namingOfUsername オブジェクト。
	 */
	protected void setNamingOfUsername(String namingOfUsername) {
		this.namingOfUsername = namingOfUsername;
	}

	/**
	 * namingOfPassword を取得します。
	 *
	 * @return namingOfPassword オブジェクト。
	 */
	public String getNamingOfPassword() {
		return this.namingOfPassword;
	}

	/**
	 * namingOfPassword を設定します。
	 *
	 * @param namingOfPassword namingOfPassword オブジェクト。
	 */
	protected void setNamingOfPassword(String namingOfPassword) {
		this.namingOfPassword = namingOfPassword;
	}

	/**
	 * namingOfSignonToken を取得します。
	 *
	 * @return namingOfSignonToken オブジェクト。
	 */
	public String getNamingOfSignonToken() {
		return this.namingOfSignonToken;
	}

	/**
	 * namingOfSignonToken を設定します。
	 *
	 * @param namingOfSignonToken namingOfSignonToken オブジェクト。
	 */
	protected void setNamingOfSignonToken(String namingOfSignonToken) {
		this.namingOfSignonToken = namingOfSignonToken;
	}

	/**
	 * namingOfSignoffSignature を取得します。
	 *
	 * @return namingOfSignoffSignature オブジェクト。
	 */
	public String getNamingOfSignoffSignature() {
		return this.namingOfSignoffSignature;
	}

	/**
	 * namingOfSignoffSignature を設定します。
	 *
	 * @param namingOfSignoffSignature namingOfSignoffSignature オブジェクト。
	 */
	protected void setNamingOfSignoffSignature(String namingOfSignoffSignature) {
		this.namingOfSignoffSignature = namingOfSignoffSignature;
	}

	/**
	 * proxy を取得します。
	 *
	 * @return proxy オブジェクト。
	 */
	public HttpHost getProxy() {
		return this.proxy;
	}

	/**
	 * proxy を設定します。
	 *
	 * @param proxy proxy オブジェクト。
	 */
	protected void setProxy(HttpHost proxy) {
		this.proxy = proxy;
	}

	/**
	 * providerURL を取得します。
	 *
	 * @return providerURL オブジェクト。
	 */
	public String getProviderURL() {
		return this.providerURL;
	}

	/**
	 * providerURL を設定します。
	 *
	 * @param providerURL providerURL オブジェクト。
	 */
	protected void setProviderURL(String providerURL) {
		this.providerURL = providerURL;
	}

	/**
	 * contextURL を取得します。
	 *
	 * @return contextURL オブジェクト。
	 */
	public String getContextURL() {
		return this.contextURL;
	}

	/**
	 * contextURL を設定します。
	 *
	 * @param contextURL contextURL オブジェクト。
	 */
	protected void setContextURL(String contextURL) {
		this.contextURL = contextURL;
	}


}
